<?php

namespace app\common\service;

use think\facade\Lang;
use think\facade\Log;
use think\exception\ValidateException;

class LanguageService
{
    protected $request;
    protected $config;

    public function __construct($request, $config)
    {
        $this->request = $request;
        $this->config = $config;
    }

    /**
     * 语言切换
     * @return void
     */
    public function languageSwitcher(): void
    {
        try {
            $acceptLanguageHeader = $this->request->header('Accept-Language');
            if (empty($acceptLanguageHeader)) {
                $language = $this->config['default_lang'] ?? 'zh-cn';
            } else {
                $language = $this->parseAcceptLanguage($acceptLanguageHeader);
            }
            $finalLanguage = $this->determineFinalLanguage($language);
            if ($finalLanguage) {
                Lang::setLangSet($finalLanguage);
            } else {
                $fallbackLanguage = $this->config['default_lang'] ?? 'zh-cn';
                Lang::setLangSet($fallbackLanguage);
            }
        } catch (\Throwable $e) {
            trace([
                'file'    => $e->getFile(),
                'line'    => $e->getLine(),
                'error_message' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ],'debug');
            throw new ValidateException('Failed to switch language due to an internal error.');
        }
    }

    /**
     * 解析 Accept-Language 头
     * @param string $headerValue
     * @return string
     */
    private function parseAcceptLanguage(string $headerValue): string
    {
        $languages = [];
        foreach (explode(',', $headerValue) as $lang) {
            $parts = explode(';', $lang);
            $code = trim($parts[0]);
            $q = 1.0;
            if (isset($parts[1])) {
                $qParts = explode('=', $parts[1]);
                if (isset($qParts[1])) {
                    $q = (float)trim($qParts[1]);
                }
            }
            $languages[$code] = $q;
        }

        arsort($languages);

        foreach ($languages as $langCode => $qValue) {
            if ($qValue > 0) {
                return $langCode;
            }
        }

        return 'zh-cn';
    }

    /**
     * 确定最终的语言
     * @param string $parsedLanguage
     * @return string|null
     */
    private function determineFinalLanguage(string $parsedLanguage): ?string
    {
        $allowedLanguages = $this->config['allow_lang_list'] ?? [];
        $acceptLanguageMap = $this->config['accept_language'] ?? [];

        if (in_array($parsedLanguage, $allowedLanguages)) {
            return $parsedLanguage;
        }

        foreach ($acceptLanguageMap as $acceptHeaderKey => $mappedValue) {
            if ($parsedLanguage === $acceptHeaderKey) {
                if (in_array($mappedValue, $allowedLanguages)) {
                    return $mappedValue;
                }
            } elseif ($parsedLanguage === $mappedValue) {

                if (in_array($mappedValue, $allowedLanguages)) {
                    return $mappedValue;
                }
            }
        }

        return null;
    }
}